import streamlit as st
import pandas as pd
import ast
import re
from zhipuai import ZhipuAI
from skill_apriori import Apriori


# -------------------- 初始化Session State --------------------
if 'client' not in st.session_state:
    st.session_state.client = None
if 'result' not in st.session_state:
    st.session_state.result = None
if 'debug' not in st.session_state:
    st.session_state.debug = []

# -------------------- 业务函数模块 --------------------
class SkillAnalyzer:
    def __init__(self):
        self.apriori = Apriori()
        self.df = None
        self._init_data()
        self.apriori.run()

    def _init_data(self):
        """初始化数据集"""
        try:
            self.df = pd.read_csv('processed_招聘数据.csv')
            # 确保列名正确映射
            self.df.rename(columns={'positionName': 'position'}, inplace=True)  # 新增重命名代码
            self.df['skill_list'] = self.df['skill_list'].apply(
                lambda x: [s.strip().lower() for s in ast.literal_eval(x)]
            )
        except Exception as e:
            raise RuntimeError(f"数据初始化失败: {str(e)}")

    def get_associated_skills(self, keyword):
        """关联技术推荐"""
        raw = self.apriori.get_associated_skills(keyword, 0.1)
        return {k.split('（')[0]: v for k, v in raw.items()}  # 移除支持度说明

    def get_position_requirements(self, position):
        """岗位技能查询"""
        filtered = self.df[self.df['position'].str.lower() == position.lower()]
        if filtered.empty:
            return {}

        # 统计技能出现频率
        skills = filtered['skill_list'].explode().value_counts()
        return skills.to_dict()

    def get_related_positions(self, skill):
        filtered = self.df[
            self.df['skill_list'].apply(
                lambda x: skill.lower() in [s.lower() for s in x]
            )
        ]
        if filtered.empty:
            return {}
        positions = filtered['position'].value_counts()
        return positions.to_dict()


# -------------------- AI交互模块 --------------------
class AIClient:
    def __init__(self):
        self.client = ZhipuAI(api_key=st.session_state.api_key)
        self.analyzer = SkillAnalyzer()
        self.tools = self._init_tools()
        self.debug_info = []

    def _init_tools(self):
        """初始化工具函数配置"""
        return [
            {
                "type": "function",
                "function": {
                    "name": "get_associated_skills",
                    "description": "推荐与输入技能相关的技术栈",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "keyword": {
                                "type": "string",
                                "description": "用户擅长的技能关键词，如'python'"
                            }
                        },
                        "required": ["keyword"]
                    }
                }
            },
            {
                "type": "function",
                "function": {
                    "name": "get_position_requirements",
                    "description": "获取指定岗位的技能要求",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "position": {
                                "type": "string",
                                "description": "岗位名称，如'前端开发工程师'"
                            }
                        },
                        "required": ["position"]
                    }
                }
            },
            {
                "type": "function",
                "function": {
                    "name": "get_related_positions",
                    "description": "根据技能推荐相关岗位",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "skill": {
                                "type": "string",
                                "description": "用户掌握的技能，如'数据分析'"
                            }
                        },
                        "required": ["skill"]
                    }
                }
            }
        ]

    def _extract_features(self, query):
        """自然语言特征提取"""
        features = {
            'skills': re.findall(r'([a-zA-Z]+开发|[a-zA-Z]+语言|[a-zA-Z]+框架)', query),
            'positions': re.findall(r'(工程师|开发|分析师|设计师|经理)', query),
            'match_types': []
        }

        if any(w in query for w in ['关联', '推荐', '相关']):
            features['match_types'].append('association')
        if any(w in query for w in ['需要', '要求', '掌握']):
            features['match_types'].append('requirement')
        if any(w in query for w in ['适合', '匹配', '选择']):
            features['match_types'].append('matching')

        return features

    def parse_query(self, query):
        """解析用户查询"""
        # 记录调试信息
        self.debug_info = [{
            "step": "feature_extraction",
            "result": self._extract_features(query)
        }]

        # 调用大模型解析
        response = self.client.chat.completions.create(
            model="glm-4-plus",
            messages=[{"role": "user", "content": query}],
            tools=self.tools,
            tool_choice="auto"
        )
        return response.choices[0].message

    def execute_function(self, func_name, args):
        """执行业务函数"""
        try:
            self.debug_info.append({
                "step": "function_call",
                "name": func_name,
                "args": args
            })

            if func_name == "get_associated_skills":
                result = self.analyzer.get_associated_skills(args['keyword'])
                return {"type": "association", "data": result}
            elif func_name == "get_position_requirements":
                result = self.analyzer.get_position_requirements(args['position'])
                return {"type": "requirements", "data": result}
            elif func_name == "get_related_positions":
                result = self.analyzer.get_related_positions(args['skill'])
                return {"type": "positions", "data": result}
            else:
                return {"error": "未知功能"}
        except Exception as e:
            return {"error": str(e)}

    def generate_response(self, query, results, debug_data):
        """生成包含调试信息的响应"""
        # 构建调试信息
        debug_output = "🔍 分析过程：\n"
        debug_output += f"- 原始问题：'{query}'\n"

        for i, data in enumerate(debug_data, 1):
            debug_output += f"\n🔧 步骤{i}：\n"
            debug_output += f"检测关键词: {data['keyword']}\n"
            debug_output += f"调用函数: {data['function']}(参数: {data['args']})\n"
            debug_output += f"返回结果: {data['result']}\n"

        # 构建提示词
        prompt = f"""请根据以下分析结果，用自然语言回答用户问题：
        分析结果：{results}

        回答要求：
        1. 分【核心结论】和【行业洞察】两部分
        2. 核心结论用emoji突出重点
        3. 补充岗位薪资范围等实用信息
        4. 使用亲切的口语化中文"""

        # 获取AI响应
        ai_response = self.client.chat.completions.create(
            model="glm-4-plus",
            messages=[{"role": "user", "content": prompt}]
        ).choices[0].message.content

        return f"{debug_output}\n💡 分析结果：\n{ai_response}"

    def process_query(self, query):
        """完整处理流程"""
        parsed = self.parse_query(query)
        debug_data = []
        results = []

        if hasattr(parsed, 'tool_calls'):
            for tool_call in parsed.tool_calls:
                func = tool_call.function
                args = ast.literal_eval(func.arguments)

                # 记录调试数据
                debug_entry = {
                    "keyword": args.get('keyword') or args.get('position') or args.get('skill'),
                    "function": func.name,
                    "args": args,
                    "result": None
                }

                # 执行函数
                result = self.execute_function(func.name, args)
                debug_entry["result"] = result

                debug_data.append(debug_entry)
                results.append(result)

        return self.generate_response(query, results, debug_data)


# -------------------- 回调函数模块 --------------------
def callback_handler(query):
    """统一回调处理函数"""
    try:
        client = AIClient()
        response = client.process_query(query)

        # 添加调试信息
        debug_log = "\n".join(
            [f"{item['step']}: {str(item)}" for item in client.debug_info]
        )
        return f"{response}\n\n[调试信息]\n{debug_log}"
    except Exception as e:
        return f"系统错误：{str(e)}"


# -------------------- 界面组件 --------------------
def show_skill_analysis_page():
    """技能分析页面布局"""
    st.title("🔍 智能技能分析系统")
    st.markdown("---")

    # 输入区域
    with st.container():
        col1, col2 = st.columns([3, 1])
        with col1:
            query = st.text_input("请输入您的查询（示例：我擅长Python可以做什么岗位？）", key="user_input")
        with col2:
            st.markdown("<br>", unsafe_allow_html=True)
            if st.button("开始分析", use_container_width=True):
                st.session_state.result = None
                st.session_state.debug = []
                if query:
                    with st.spinner("正在分析中，请稍候..."):
                        st.session_state.result = callback_handler(query)
                else:
                    st.error("请输入有效查询内容")

    # 结果显示区域
    if st.session_state.result:
        st.markdown("---")
        if '分析结果' in st.session_state.result:
            main_res, debug_res = st.session_state.result.split('[调试信息]', 1)

            # 核心结果展示
            with st.container():
                st.markdown('<div class="result-header">✨ 核心结论</div>', unsafe_allow_html=True)
                st.markdown(main_res.split("💡 分析结果：")[-1].strip())

            # 调试信息
            with st.expander("查看分析细节"):
                st.markdown('<div class="result-header">🔧 分析过程</div>', unsafe_allow_html=True)
                st.code(debug_res.strip(), language='log')


import streamlit as st
from streamlit_echarts import st_echarts, JsCode
import json
import os
from zhipuai import ZhipuAI
import time
import re
import altair as alt
from typing import Optional, Tuple, Dict, Any

@st.cache_data
def load_data(file_name):
    try:
        with open(file_name, "r", encoding="utf-8") as f:
            return json.load(f)
    except FileNotFoundError:
        st.error(f"数据文件 {file_name} 未找到")
        return None

class DataProcessor:
    def __init__(self, file_path):
        import pandas as pd
        self.df = pd.read_csv(file_path)

    def _filter_data(self, position, city):
        if city:
            return self.df[(self.df['positionName'].str.contains(position, case=False)) & (self.df['city'] == city)]
        return self.df[self.df['positionName'].str.contains(position, case=False)]

    def get_salary_analysis(self, position, city):
        filtered = self._filter_data(position, city)
        if len(filtered) == 0:
            return None

        def extract_salary(s):
            try:
                min_salary, max_salary = map(int, s.replace('k', '').split('-'))
                return (min_salary + max_salary) / 2
            except:
                return None

        filtered['avg_salary'] = filtered['salary'].apply(extract_salary)
        filtered = filtered.dropna(subset=['avg_salary'])

        title = f"{city if city else '全国'} {position} 岗位薪资分布"
        # 箱线图
        boxplot = alt.Chart(filtered).mark_boxplot().encode(
            x='avg_salary:Q'
        )
        # 散点图
        scatter = alt.Chart(filtered).mark_point(opacity=0.3).encode(
            x='avg_salary:Q',
            tooltip=['avg_salary:Q']
        )
        chart = boxplot + scatter

        return title, chart

    def get_city_demand(self, city):
        city_data = self.df[self.df['city'] == city]
        if len(city_data) == 0:
            return None
        title = f"{city} 岗位需求分布"
        # 柱状图
        bar = alt.Chart(city_data).mark_bar().encode(
            x=alt.X('positionName:N', sort='-y'),
            y='count()',
            tooltip=['positionName:N', 'count()']
        )
        # 折线图
        line = alt.Chart(city_data).mark_line(color='red').encode(
            x=alt.X('positionName:N', sort='-y'),
            y='count()'
        )
        chart = bar + line

        return title, chart

    def get_skill_analysis(self, skill):
        filtered = self.df[self.df['skillLables'].apply(lambda x: skill.lower() in str(x).lower())]
        if len(filtered) == 0:
            return None

        def extract_salary(s):
            try:
                min_salary, max_salary = map(int, s.replace('k', '').split('-'))
                return (min_salary + max_salary) / 2
            except:
                return None

        filtered['avg_salary'] = filtered['salary'].apply(extract_salary)
        filtered = filtered.dropna(subset=['avg_salary'])

        title = f"{skill} 技能薪资分布"
        # 箱线图
        boxplot = alt.Chart(filtered).mark_boxplot().encode(
            x='avg_salary:Q'
        )
        # 散点图
        scatter = alt.Chart(filtered).mark_point(opacity=0.3).encode(
            x='avg_salary:Q',
            tooltip=['avg_salary:Q']
        )
        chart = boxplot + scatter

        return title, chart

    def get_education_analysis(self, city):
        filtered = self.df if not city else self.df[self.df['city'] == city]
        if len(filtered) == 0:
            return None

        def extract_salary(s):
            try:
                min_salary, max_salary = map(int, s.replace('k', '').split('-'))
                return (min_salary + max_salary) / 2
            except:
                return None

        filtered['avg_salary'] = filtered['salary'].apply(extract_salary)
        filtered = filtered.dropna(subset=['avg_salary'])

        title = f"{'全国' if not city else city} 学历与薪资关系"
        # 箱线图
        boxplot = alt.Chart(filtered).mark_boxplot().encode(
            x='education:N',
            y='avg_salary:Q'
        )
        # 散点图
        scatter = alt.Chart(filtered).mark_point(opacity=0.3).encode(
            x='education:N',
            y='avg_salary:Q',
            tooltip=['education:N', 'avg_salary:Q']
        )
        chart = boxplot + scatter

        return title, chart

    def get_experience_analysis(self, position):
        filtered = self.df[self.df['positionName'].str.contains(position, case=False)]
        if len(filtered) == 0:
            return None

        def extract_salary(s):
            try:
                min_salary, max_salary = map(int, s.replace('k', '').split('-'))
                return (min_salary + max_salary) / 2
            except:
                return None

        def extract_experience(wy):
            if wy == '不限':
                return 0
            try:
                min_exp, max_exp = map(int, wy.replace('年', '').split('-'))
                return (min_exp + max_exp) / 2
            except:
                return 0

        filtered['avg_salary'] = filtered['salary'].apply(extract_salary)
        filtered['avg_experience'] = filtered['workYear'].apply(extract_experience)
        filtered = filtered.dropna(subset=['avg_salary', 'avg_experience'])

        title = f"{position} 岗位经验要求分布"
        # 箱线图
        boxplot = alt.Chart(filtered).mark_boxplot().encode(
            x='avg_experience:N',
            y='avg_salary:Q'
        )
        # 散点图
        scatter = alt.Chart(filtered).mark_point(opacity=0.3).encode(
            x='avg_experience:N',
            y='avg_salary:Q',
            tooltip=['avg_experience:N', 'avg_salary:Q']
        )
        chart = boxplot + scatter

        return title, chart

class QueryProcessor:
    def __init__(self, df_processor: DataProcessor):
        self.dp = df_processor
        self.intent_patterns = {
            'salary': r'(薪资|工资|薪水|平均薪资|多少钱|多少k|多少K).*(算法|Java|Python|开发|工程师|岗位|职位)',
            'city_demand': r'(北京|上海|广州|深圳|福州).*(需求|热门|岗位)',
            'skill': r'(要求|需要|掌握).*(Python|Java|机器学习|深度学习|大数据)',
            'education': r'(学历|本科|硕士|博士).*(影响|薪资|工资|薪水)',
            'experience': r'(经验|年限|年资).*(要求|影响|薪资)'
        }

    def _get_context_info(self) -> Dict[str, Any]:
        context = {}
        if "messages" not in st.session_state:
            return context
        recent_msgs = st.session_state.messages[-3:]
        for msg in reversed(recent_msgs):
            if msg["role"] == "assistant" and "stats" in msg:
                stats = msg["stats"]
                if "position" in stats and "position" not in context:
                    context["position"] = stats["position"]
                if "city" in stats and "city" not in context:
                    context["city"] = stats["city"]
                if "skill" in stats and "skill" not in context:
                    context["skill"] = stats["skill"]
        return context

    def detect_intent(self, query: str) -> str:
        context = self._get_context_info()
        if any(word in query for word in ["薪资", "工资", "薪水", "多少钱"]):
            if context.get("position") or re.search(r'(算法|Java|Python|开发|工程师)', query):
                return 'salary'
        if any(word in query for word in ["需求", "热门", "岗位"]):
            if context.get("city") or re.search(r'(北京|上海|广州|深圳|福州)', query):
                return 'city_demand'
        for intent, pattern in self.intent_patterns.items():
            if re.search(pattern, query):
                return intent
        return 'general'

    def _build_context_prompt(self, current_query: str) -> str:
        context = []
        if "messages" not in st.session_state:
            return current_query
        recent_msgs = st.session_state.messages[-5:] if len(
            st.session_state.messages) > 5 else st.session_state.messages
        for msg in recent_msgs:
            if msg["role"] == "user":
                context.append(f"用户提问: {msg['content']}")
            elif msg["role"] == "assistant" and "stats" in msg:
                stats = msg["stats"]
                if "position" in stats:
                    context.append(f"之前讨论的岗位: {stats['position']}")
                if "city" in stats:
                    context.append(f"之前讨论的城市: {stats['city']}")
                if "skill" in stats:
                    context.append(f"之前讨论的技能: {stats['skill']}")
        context.append(f"当前问题: {current_query}")
        return "\n".join(context)

    def process_query(self, query: str) -> Optional[Tuple[str, alt.Chart, dict]]:
        context = self._get_context_info()
        intent = self.detect_intent(query)

        if intent == 'salary':
            position = context.get("position", None)
            city = context.get("city", None)
            positions = ['算法', 'Java', 'Python', '开发', '工程师']
            for p in positions:
                if p in query:
                    position = p
                    break
            if not position:
                position = 'Java'
            cities = ['北京', '上海', '广州', '深圳']
            for c in cities:
                if c in query:
                    city = c
                    break

            # 处理北上广深Java岗位平均薪资查询
            if position == 'Java' and any(city in query for city in cities):
                cities = ['北京', '上海', '广州', '深圳']
                data = []
                for city in cities:
                    result = self.dp.get_salary_analysis(position, city)
                    if result:
                        title, chart = result
                        filtered = self.dp._filter_data(position, city)
                        if 'avg_salary' in filtered.columns:
                            avg_salary = filtered['avg_salary'].mean()
                            data.append({
                                'city': city,
                                'avg_salary': avg_salary
                            })
                if data:
                    df = pd.DataFrame(data)
                    title = "北上广深Java岗位平均薪资分布"
                    chart = alt.Chart(df).mark_bar().encode(
                        x=alt.X('city:N', title='城市'),
                        y=alt.Y('avg_salary:Q', title='平均薪资 (k)'),
                        tooltip=['city', 'avg_salary']
                    ).properties(width=600, title=title)
                    stats = {
                        'position': position,
                        'cities': cities,
                        'avg_salaries': df['avg_salary'].tolist()
                    }
                    return title, chart, stats
                return f"在本地数据集未能查询到北上广深{position}岗位的薪资数据", None, None

            result = self.dp.get_salary_analysis(position, city)
            if result:
                title, chart = result
                filtered = self.dp._filter_data(position, city)
                if 'avg_salary' in filtered.columns:
                    stats = {
                        'position': position,
                        'city': city if city else '全国',
                        'avg_salary': filtered['avg_salary'].mean(),
                        'min_salary': filtered['avg_salary'].min(),
                        'max_salary': filtered['avg_salary'].max(),
                        'count': len(filtered)
                    }
                else:
                    stats = {
                        'position': position,
                        'city': city if city else '全国',
                        'count': len(filtered)
                    }
                return title, chart, stats
            return f"在本地数据集未能查询到{city if city else ''}{position}岗位的薪资数据", None, None

        elif intent == 'city_demand':
            city = context.get("city", None)
            cities = ['北京', '上海', '广州', '深圳', '福州']
            for c in cities:
                if c in query:
                    city = c
                    break
            if not city:
                return "请指定要查询的城市，例如：北京的需求如何？", None, None
            result = self.dp.get_city_demand(city)
            if result:
                title, chart = result
                city_data = self.dp.df[self.dp.df['city'] == city]
                top_position = city_data['positionName'].value_counts().index[0]
                stats = {
                    'city': city,
                    'top_position': top_position,
                    'position_count': city_data['positionName'].value_counts().max(),
                    'total_jobs': len(city_data)
                }
                return title, chart, stats
            return f"在本地数据集未能查询到{city}市的岗位需求数据", None, None

        elif intent == 'skill':
            skill = context.get("skill", None)
            skills = ['Python', 'Java', '机器学习', '深度学习']
            for s in skills:
                if s in query:
                    skill = s
                    break
            if not skill:
                return "请指定要查询的技能，例如：Python技能的要求是什么？", None, None
            result = self.dp.get_skill_analysis(skill)
            if result:
                title, chart = result
                filtered = self.dp.df[self.dp.df['skillLables'].apply(lambda x: skill.lower() in str(x).lower())]
                if 'avg_salary' in filtered.columns:
                    stats = {
                        'skill': skill,
                        'avg_salary': filtered['avg_salary'].mean(),
                        'company_sizes': filtered['companySize'].value_counts().to_dict(),
                        'count': len(filtered)
                    }
                else:
                    stats = {
                        'skill': skill,
                        'count': len(filtered)
                    }
                return title, chart, stats
            return f"在本地数据集未能查询到{skill}技能的相关数据", None, None

        elif intent == 'education':
            city = context.get("city", None)
            cities = ['北京', '上海', '广州', '深圳']
            for c in cities:
                if c in query:
                    city = c
                    break
            result = self.dp.get_education_analysis(city)
            if result:
                title, chart = result
                filtered = self.dp.df if not city else self.dp.df[self.dp.df['city'] == city]

                if 'avg_salary' in filtered.columns:
                    stats = filtered.groupby('education').agg(
                        avg_salary=('avg_salary', 'mean'),
                        count=('education', 'count')
                    ).to_dict()
                    stats['city'] = city if city else '全国'
                else:
                    stats = {
                        'city': city if city else '全国',
                        'count': len(filtered)
                    }
                return title, chart, stats
            return f"在本地数据集未能查询到{'全国' if not city else city}的学历与薪资关系数据", None, None

        elif intent == 'experience':
            position = context.get("position", None)
            positions = ['算法', 'Java', 'Python', '开发']
            for p in positions:
                if p in query:
                    position = p
                    break
            if not position:
                return "请指定要查询的岗位，例如：Java开发的经验要求是什么？", None, None
            result = self.dp.get_experience_analysis(position)
            if result:
                title, chart = result
                filtered = self.dp.df[self.dp.df['positionName'].str.contains(position, case=False)]

                if 'avg_experience' in filtered.columns:
                    stats = {
                        'position': position,
                        'avg_experience': filtered['avg_experience'].mean(),
                        'count': len(filtered)
                    }
                else:
                    stats = {
                        'position': position,
                        'count': len(filtered)
                    }
                return title, chart, stats
            return f"在本地数据集未能查询到{position}岗位的经验要求数据", None, None

        return None

def configure_chart(chart: alt.Chart) -> alt.Chart:
    return chart.configure_view(
        strokeWidth=0,
        fill='#f8f9fa'
    ).configure_axis(
        labelFontSize=12,
        titleFontSize=14,
        gridColor='#e9ecef'
    ).configure_title(
        fontSize=16,
        anchor='start',
        color='#2b2d42'
    ).configure_legend(
        titleFontSize=12,
        labelFontSize=11,
        orient='right',
        labelColor='#6c757d'
    ).configure_header(
        labelOrient='bottom',
        titleFontSize=13
    )

def analyze_city_salary():
    st.title("2023年城市平均薪资可视化分析")
    data = load_data("city_salary.json")
    if not data: return
    with st.sidebar:
        st.header("过滤条件")
        city_class = st.selectbox("城市类别", ["全部", "一线城市", "非一线城市"])
        min_salary = st.slider("最低薪资（k）", 0, 50, 10)
    TIER1_CITIES = ["北京", "上海", "广州", "深圳", "杭州", "成都", "南京", "武汉", "苏州", "重庆"]
    filtered = {
        city: salary for city, salary in data.items()
        if (city_class == "全部" or
            (city_class == "一线城市" and city in TIER1_CITIES) or
            (city_class == "非一线城市" and city not in TIER1_CITIES)) and
           salary >= min_salary
    }
    sorted_items = sorted(filtered.items(), key=lambda x: x[1], reverse=True)
    options = {
        "xAxis": {"data": [k[0] for k in sorted_items], "axisLabel": {"rotate": 45}},
        "yAxis": {"name": "平均薪资（k）"},
        "series": [{
            "type": "bar",
            "data": [k[1] for k in sorted_items],
            "itemStyle": {"color": "#5470c6"}
        }],
        "tooltip": {"formatter": JsCode("(p) => `${p.name}: ${p.value}k`").js_code}
    }
    st_echarts(options, height=500)

def analyze_industry_distribution():
    st.title("行业招聘需求分析")
    data = load_data("industry_distribution.json")
    if not data: return
    with st.sidebar:
        st.header("过滤条件")
        min_count = st.slider("最低职位数", 0, 1000, 100)
        excluded = st.multiselect("排除行业", [d["industry"] for d in data])
    filtered = [d for d in data if d["count"] >= min_count and d["industry"] not in excluded]
    options = {
        "series": [{
            "type": "pie",
            "radius": "55%",
            "data": [{"name": d["industry"], "value": d["count"]} for d in filtered],
            "emphasis": {"itemStyle": {"shadowBlur": 10}}
        }],
        "legend": {"orient": "vertical", "left": "left"}
    }
    st_echarts(options, height=600)

def analyze_position_salaries():
    st.title("跨城市同岗位薪资对比")
    data = load_data("position_salaries.json")
    if not data:
        st.error("数据加载失败")
        return
    with st.sidebar:
        st.header("过滤设置")
        selected_industry = st.selectbox("选择行业", list({d["industry"] for d in data}))
        min_samples = st.slider("最小样本量", 10, 100, 20)
    filtered = [
        d for d in data
        if d["industry"] == selected_industry and
           d["sample_size"] >= min_samples
    ]
    if filtered:
        options = {
            "xAxis": {"type": "category", "data": [f"{d['city']}-{d['position']}" for d in filtered]},
            "yAxis": {"name": "薪资范围 (k)"},
            "series": [{
                "type": "boxplot",
                "data": [[d["min"], d["q1"], d["median"], d["q3"], d["max"]] for d in filtered],
                "itemStyle": {"color": "#5470c6"}
            }],
            "tooltip": {
                "formatter": JsCode("""
                    function(params) {
                        return `${params.name}<br/>
                            最小值: ${params.value[0]}k<br/>
                            下四分位: ${params.value[1]}k<br/>
                            中位数: ${params.value[2]}k<br/>
                            上四分位: ${params.value[3]}k<br/>
                            最大值: ${params.value[4]}k`;
                    }
                """).js_code
            }
        }
        st_echarts(options, height=600)
    else:
        st.warning("无符合条件的数据")

def analyze_education_promotion():
    st.title("学历与晋升速度相关性分析")
    data = load_data("education_promotion.json")
    if not data: return
    with st.sidebar:
        st.header("分析设置")
        city_group = st.radio("城市群", ["长三角", "珠三角"])
        exclude_management = st.toggle("排除管理岗", True)
    target = "technical" if exclude_management else "management"
    edu_data = data["city_groups"][city_group][target]
    options = {
        "xAxis": {"data": list(edu_data["硕士"].keys())},
        "yAxis": {"name": "平均薪资（k）"},
        "series": [
            {"name": "硕士", "type": "line", "data": list(edu_data["硕士"].values())},
            {"name": "本科", "type": "line", "data": list(edu_data["本科"].values())}
        ]
    }
    st_echarts(options, height=600)

def analyze_tag_frequency():
    st.title("职位标签分布分析")
    data = load_data("tag_frequency.json")
    if not data: return
    with st.sidebar:
        st.header("过滤条件")
        min_freq = st.slider("最低出现次数", 0, 500, 50)
        excluded = st.multiselect("排除标签", [d["name"] for d in data])
    filtered = [d for d in data if d["value"] >= min_freq and d["name"] not in excluded]
    options = {
        "series": [{
            "type": "wordCloud",
            "data": [{"name": d["name"], "value": d["value"]} for d in filtered],
            "textStyle": {"color": JsCode("() => randomColor()").js_code}
        }]
    }
    st_echarts(options, height=600)

def chat_interface():
    st.title("💬 智能招聘助手")
    if "messages" not in st.session_state:
        st.session_state.messages = [{
            "role": "assistant",
            "content": "您好！我是智能招聘分析助手，可以为您解答：\n"
                       "🔸 岗位薪资分布 \n🔸 城市招聘需求 \n🔸 技能要求趋势 \n"
                       "🔸 学历经验影响 \n🔸 行业趋势分析\n\n"
                       "支持上下文理解"
        }]
    for msg in st.session_state.messages:
        with st.chat_message(msg["role"]):
            st.write(msg["content"])
            if "chart" in msg:
                st.altair_chart(configure_chart(msg["chart"]))
    if prompt := st.chat_input("请输入招聘相关问题（如：北京Java工程师薪资）"):
        st.session_state.messages.append({"role": "user", "content": prompt})
        with st.chat_message("user"):
            st.write(prompt)
        result = st.session_state.query_processor.process_query(prompt)
        with st.chat_message("assistant"):
            if result:
                title, chart, stats = result
                if chart:
                    st.write(title)
                    st.altair_chart(configure_chart(chart))
                    if stats and st.session_state.api_key:  # 确保API密钥存在
                        try:
                            client = ZhipuAI(api_key=st.session_state.api_key)
                            context_prompt = st.session_state.query_processor._build_context_prompt(prompt)
                            ai_prompt = (
                                f"对话上下文:\n{context_prompt}\n\n"
                                f"本地查询结果摘要: {stats}\n"
                                "请用自然语言解释这些数据，用简洁易懂的方式描述关键发现，"
                                "并给出一些合理的分析建议。使用中文回答。"
                            )
                            with st.spinner("🔍 正在生成分析解释..."):
                                response = client.chat.completions.create(
                                    model=st.session_state.model_type,
                                    messages=[{"role": "user", "content": ai_prompt}],
                                    temperature=0.3,
                                    max_tokens=1024
                                )
                                ai_response = response.choices[0].message.content
                                st.write(ai_response)
                                st.session_state.messages.append({
                                    "role": "assistant",
                                    "content": title,
                                    "chart": chart,
                                    "stats": stats
                                })
                                st.session_state.messages.append({
                                    "role": "assistant",
                                    "content": ai_response
                                })
                        except Exception as e:
                            st.error(f"AI解释生成失败: {str(e)}")
                    else:
                        st.session_state.messages.append({
                            "role": "assistant",
                            "content": title,
                            "chart": chart,
                            "stats": stats
                        })
                else:
                    st.write(title)
                    st.session_state.messages.append({
                        "role": "assistant",
                        "content": title
                    })
                    if st.session_state.api_key:  # 确保API密钥存在
                        try:
                            client = ZhipuAI(api_key=st.session_state.api_key)
                            context_prompt = st.session_state.query_processor._build_context_prompt(prompt)
                            ai_prompt = (
                                f"用户查询了本地数据库，但未找到相关信息：{title}\n"
                                f"对话上下文:\n{context_prompt}\n\n"
                                "请用自然语言回答用户的问题，提供相关行业知识、趋势或建议。使用中文回答。"
                            )
                            with st.spinner("🔍 正在分析..."):
                                response = client.chat.completions.create(
                                    model=st.session_state.model_type,
                                    messages=[{"role": "user", "content": ai_prompt}],
                                    temperature=0.3,
                                    max_tokens=1024
                                )
                                ai_response = response.choices[0].message.content
                                st.write(ai_response)
                                st.session_state.messages.append({
                                    "role": "assistant",
                                    "content": ai_response
                                })
                        except Exception as e:
                            st.error(f"请求失败: {str(e)}")
            else:
                if not st.session_state.api_key:
                    st.warning("⚠️ 请输入有效的API密钥")
                    return
                try:
                    client = ZhipuAI(api_key=st.session_state.api_key)
                    with st.spinner("🔍 正在分析..."):
                        context_prompt = st.session_state.query_processor._build_context_prompt(prompt)
                        response = client.chat.completions.create(
                            model=st.session_state.model_type,
                            messages=[{"role": "user", "content": context_prompt}],
                            temperature=0.3,
                            max_tokens=1024
                        )
                        ai_response = response.choices[0].message.content
                        st.write(ai_response)
                        st.session_state.messages.append({
                            "role": "assistant",
                            "content": ai_response
                        })
                except Exception as e:
                    st.error(f"请求失败: {str(e)}")

def visualization_interface():
    st.title("📊 招聘数据可视化分析")
    visualization_options = [
        "城市薪资对比",
        "行业需求分布",
        "岗位薪资分析",
        "教育晋升分析",
        "职位标签分析"
    ]
    visualization_type = st.radio("选择分析类型", visualization_options)
    if visualization_type == "城市薪资对比":
        analyze_city_salary()
    elif visualization_type == "行业需求分布":
        analyze_industry_distribution()
    elif visualization_type == "岗位薪资分析":
        analyze_position_salaries()
    elif visualization_type == "教育晋升分析":
        analyze_education_promotion()
    elif visualization_type == "职位标签分析":
        analyze_tag_frequency()

def main():
    st.set_page_config(page_title="智能招聘助手", layout="wide", page_icon="🤖")
    if 'data_processor' not in st.session_state:
        try:
            st.session_state.data_processor = DataProcessor("拉勾网2023招聘数据.csv")
            st.session_state.query_processor = QueryProcessor(st.session_state.data_processor)
        except Exception as e:
            st.error(f"数据初始化失败: {str(e)}")
            return
    with st.sidebar:
        st.title('🔍 智能招聘分析助手')
        st.session_state.api_key = st.text_input('请输入API Token:', type='password')
        st.session_state.model_type = st.selectbox("选择模型", ["glm-4-flash", "glm-4-plus"])
        st.button('🔄 清空对话', on_click=lambda: st.session_state.clear())
        st.markdown("""
            ---
            **使用说明**  
            1. 输入API密钥  
            2. 支持自然语言提问例如：  
               - 北京的Java工程师薪资如何？  
               - 福州需求最大的岗位是什么？  
               - 硕士学历对薪资的影响  
               - Python开发的经验要求分布  
            """)
        main_option = st.radio(
            "选择功能模块",
            ["可视化分析", "聊天对话", "技能分析"]
        )
    if main_option == "可视化分析":
        visualization_interface()
    elif main_option == "聊天对话":
        chat_interface()
    elif main_option == "技能分析":
        show_skill_analysis_page()

if __name__ == "__main__":
    main()